package com.gitee.feizns.dynamic;

import com.gitee.feizns.dynamic.convert.MethodConverterUtils;
import com.gitee.feizns.dynamic.time.Times;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.Year;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalQuery;
import java.util.Arrays;
import java.util.Date;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;

/**
 * <b>日期操作工具类型</b>
 * @author feizns
 * @since 2022/11/11
 */
public abstract class DateUtils {

    //==================================转换成时间戳===================================
    //==================================转换成时间戳===================================
    //==================================转换成时间戳===================================

    /**
     * <b>将日期转成时间戳</b>
     * <p>
     *     适用于：[java.util.Date, java.sql.Date, java.sql.Time, java.sql.Timestamp]
     * </p>
     * @param date {@link Date}
     * @return 返回时间戳
     */
    public static Long milliseconds(Date date) {
        return Optional.ofNullable(date).map(Date::getTime).orElse(null);
    }

    /**
     * <b>将{@link TemporalAccessor}转成时间戳（默认使用对应的最小值）</b>
     * <pre>{@code
     *     public static void main(String[] args) {
     *         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
     *         System.out.println(sdf.format(new Date(milliseconds(Year.now()))));             //2023-01-01 00:00:00.000
     *         System.out.println(sdf.format(new Date(milliseconds(Year.now().atMonth(2)))));  //2023-02-01 00:00:00.000
     *         System.out.println(sdf.format(new Date(milliseconds(LocalDate.now()))));        //2023-01-09 00:00:00.000
     *         System.out.println(sdf.format(new Date(milliseconds(LocalDateTime.now()))));    //2023-01-09 23:45:44.716
     *     }
     * }</pre>
     * @see #getOrDefault(TemporalAccessor, ChronoField, Function)
     * @param temporalAccessor {@link TemporalAccessor}
     * @return 返回时间戳
     */
    public static Long milliseconds(TemporalAccessor temporalAccessor) {
        return Optional.ofNullable(temporalAccessor).map(temporal -> temporal.query(instantQuery()).toEpochMilli()).orElse(null);
    }

    /**
     * <b>将Object类型数据尝试转换为时间戳</b>
     * @param source 原数据
     * @return 返回该日期的时间戳
     */
    public static Long milliseconds(Object source) {
        if ( source != null ) {
            if ( source instanceof Number )
                return ((Number) source).longValue();
            if ( source instanceof Date )
                return ((Date) source).getTime();
            else if ( source instanceof TemporalAccessor )
                return DateUtils.milliseconds((TemporalAccessor) source);
            if ( source instanceof String ) {
                ZonedDateTime zonedDateTime = toZonedDateTime(source);
                return zonedDateTime != null ? zonedDateTime.toInstant().toEpochMilli() : null;
            }
        }
        return null;
    }

    //===============================转换成java.util.Date=============================
    //===============================转换成java.util.Date=============================
    //===============================转换成java.util.Date=============================

    /**
     * <b>从时间戳转为{@link Date}</b>
     * @param milliseconds 时间戳毫秒数
     * @return {@link Date}
     */
    public static Date from(Long milliseconds) {
        return Optional.ofNullable(milliseconds).map(Date::new).orElse(null);
    }

    /**
     * <b>从{@link TemporalAccessor}转{@link Date}</b>
     * <pre>{@code
     *     public static void main(String[] args) {
     *         System.out.println(from(Year.now()));           //Sun Jan 01 00:00:00 CST 2023
     *         System.out.println(from(YearMonth.now()));      //Sun Jan 01 00:00:00 CST 2023
     *         System.out.println(from(LocalDate.now()));      //Tue Jan 10 00:00:00 CST 2023
     *         System.out.println(from(LocalTime.now()));      //Mon Jan 03 12:12:03 CST 1
     *         System.out.println(from(LocalDateTime.now()));  //Tue Jan 10 12:17:46 CST 2023
     *     }
     * }</pre>
     * @param temporalAccessor {@link TemporalAccessor}
     * @return {@link Date}
     */
    public static Date from(TemporalAccessor temporalAccessor) {
        return new Date(milliseconds(temporalAccessor));
    }

    /**
     * <b>从{@link String}转{@link Date}</b>
     * @param date 字符串日期
     * @return {@link Date}，解析失败返回null
     */
    public static Date from(String date) {
        ZonedDateTime zonedDateTime = toZonedDateTime(date);
        return zonedDateTime != null ? Date.from(zonedDateTime.toInstant()) : null;
    }

    /**
     * <b>将{@link Object}类型数据尝试转换为{@link Date}</b>
     * @param source 未知类型对象
     * @return {@link Date}
     * @see #milliseconds(Object)
     */
    public static Date from(Object source) {
        return Optional.ofNullable(milliseconds(source)).map(Date::new).orElse(null);
    }

    /**
     * <b>从String转Date</b>
     * @param date 字符串日期
     * @return 按日期格式顺序解析，返回第一个解析成功的，解析失败返回null
     */
    public static Date from(String date, String... pattern) {
        return parse(date, pattern);
    }

    //=============================转换成java.time.Instant=================================
    //=============================转换成java.time.Instant=================================
    //=============================转换成java.time.Instant=================================

    /**
     * <b>从时间戳转{@link Instant}</b>
     * @param milliseconds 时间戳
     * @return {@link Instant}
     */
    public static Instant toInstant(Long milliseconds) {
        return Optional.ofNullable(milliseconds)
                .map(Instant::ofEpochMilli)
                .orElse(null);
    }

    /**
     * <b>从{@link TemporalAccessor}转{@link Instant}</b>
     * <pre>{@code
     *      public static void main(String[] args) {
     *         System.out.println(toInstant(Year.now()));            //2022-12-31T16:00:00Z
     *         System.out.println(toInstant(YearMonth.now()));       //2022-12-31T16:00:00Z
     *         System.out.println(toInstant(LocalDate.now()));       //2023-01-09T16:00:00Z
     *         System.out.println(toInstant(LocalTime.now()));       //0001-01-01T02:37:47.241Z
     *         System.out.println(toInstant(LocalDateTime.now()));   //2023-01-10T02:43:30.241Z
     *     }
     * }</pre>
     * @param temporalAccessor {@link TemporalAccessor}
     * @return {@link Instant}
     */
    public static Instant toInstant(TemporalAccessor temporalAccessor) {
        return Optional.ofNullable(temporalAccessor).map(temporal -> temporal.query(instantQuery())).orElse(null);
    }

    /**
     * <b>从{@link Date}转{@link Instant}</b>
     * @param date {@link Date}
     * @return {@link Instant}
     */
    public static Instant toInstant(Date date) {
        return Optional.ofNullable(date).map(Date::toInstant).orElse(null);
    }

    /**
     * <b>从{@link String}转{@link Instant}</b>
     * @param date {@link String}
     * @return {@link Instant}
     */
    public static Instant toInstant(String date) {
        ZonedDateTime zonedDateTime = toZonedDateTime(Times.parse(date));
        return zonedDateTime != null ? zonedDateTime.toInstant() : null;
    }

    /**
     * <b>从未知对象转{@link Instant}</b>
     * @param source {@link Object}
     * @return {@link Instant}
     */
    public static Instant toInstant(Object source) {
        return parse(source, Instant.class);
    }

    //=============================转换成java.time.Year====================================
    //=============================转换成java.time.Year====================================
    //=============================转换成java.time.Year====================================

    /**
     * <b>从时间戳转{@link Year}</b>
     * @param milliseconds 时间戳
     * @return {@link Year}
     */
    public static Year toYear(Long milliseconds) {
        return toYear(toInstant(milliseconds));
    }

    /**
     * <b>从{@link TemporalAccessor}转{@link Year}</b>
     * <pre>{@code
     *     public static void main(String[] args) {
     *         System.out.println(toYear(YearMonth.now()));    //2023
     *         System.out.println(toYear(LocalDate.now()));    //2023
     *         System.out.println(toYear(LocalTime.now()));    //1
     *         System.out.println(toYear(LocalDateTime.now()));//2023
     *     }
     * }</pre>
     * @param temporalAccessor {@link TemporalAccessor}
     * @return {@link Year}
     */
    public static Year toYear(TemporalAccessor temporalAccessor) {
        return Optional.ofNullable(temporalAccessor).map(temporal -> temporal.query(yearQuery())).orElse(null);
    }

    /**
     * <b>从{@link Date}转{@link Year}</b>
     * @param date {@link Date}
     * @return {@link Year}
     */
    public static Year toYear(Date date) {
        return Year.from(toLocalDate(date));
    }

    /**
     * <b>从{@link String}转{@link Year}</b>
     * @param date {@link String}
     * @return {@link Year}
     */
    public static Year toYear(String date) {
        return Times.parse(date, Year.class);
    }

    /**
     * <b>从未知对象转{@link Year}</b>
     * @param source {@link Object}
     * @return {@link Year}
     */
    public static Year toYear(Object source) {
        return parse(source, Year.class);
    }

    //=============================转换成java.time.YearMonth=================================
    //=============================转换成java.time.YearMonth=================================
    //=============================转换成java.time.YearMonth=================================

    /**
     * <b>从时间戳转{@link YearMonth}</b>
     * @param milliseconds 时间戳
     * @return {@link YearMonth}
     */
    public static YearMonth toYearMonth(Long milliseconds) {
        return Optional.ofNullable(toInstant(milliseconds)).map(YearMonth::from).orElse(null);
    }

    /**
     * <b>从{@link TemporalAccessor}转{@link YearMonth}</b>
     * <pre>{@code
     *     public static void main(String[] args) {
     *         System.out.println(toYearMonth(Year.now()));            //2023-01
     *         System.out.println(toYearMonth(YearMonth.now()));       //2023-01
     *         System.out.println(toYearMonth(LocalDate.now()));       //2023-01
     *         System.out.println(toYearMonth(LocalTime.now()));       //0001-01
     *         System.out.println(toYearMonth(LocalDateTime.now()));   //2023-01
     *     }
     * }</pre>
     * @param temporalAccessor {@link TemporalAccessor}
     * @return {@link YearMonth}
     */
    public static YearMonth toYearMonth(TemporalAccessor temporalAccessor) {
        return Optional.ofNullable(temporalAccessor).map(temporal -> temporal.query(yearMonthQuery())).orElse(null);
    }

    /**
     * <b>从{@link Date}转{@link YearMonth}</b>
     * <pre>{@code
     *     public static void main(String[] args) {
     *         System.out.println(toYearMonth(Year.now()));            //2023-01
     *         System.out.println(toYearMonth(YearMonth.now()));       //2023-01
     *         System.out.println(toYearMonth(LocalDate.now()));       //2023-01
     *         System.out.println(toYearMonth(LocalTime.now()));       //0001-01
     *         System.out.println(toYearMonth(LocalDateTime.now()));   //2023-01
     *     }
     * }</pre>
     * @param date {@link Date}
     * @return {@link YearMonth}
     */
    public static YearMonth toYearMonth(Date date) {
        return YearMonth.from(toLocalDate(date));
    }

    /**
     * <b>从{@link String}转{@link YearMonth}</b>
     * @param date {@link String}
     * @return {@link YearMonth}
     */
    public static YearMonth toYearMonth(String date) {
        return Times.parse(date, YearMonth.class);
    }

    /**
     * <b>从未知对象转{@link YearMonth}</b>
     * @param source {@link Object}
     * @return {@link YearMonth}
     */
    public static YearMonth toYearMonth(Object source) {
        return parse(source, YearMonth.class);
    }

    //=============================转换成java.time.LocalDate===========================
    //=============================转换成java.time.LocalDate===========================
    //=============================转换成java.time.LocalDate===========================

    /**
     * <b>从时间戳转{@link LocalDate}</b>
     * @param milliseconds 时间戳
     * @return {@link LocalDate}
     */
    public static LocalDate toLocalDate(Long milliseconds) {
        return atDefaultZoneMapTo(toInstant(milliseconds), ZonedDateTime::toLocalDate);
    }

    /**
     * <b>从Date转换为{@link LocalDate}</b>
     * @param date {@link Date}
     * @return {@link LocalDate}
     */
    public static LocalDate toLocalDate(Date date) {
        return Optional.ofNullable(date).map(Date::toInstant).map(instant -> atDefaultZoneMapTo(instant, ZonedDateTime::toLocalDate)).orElse(null);
    }

    /**
     * <b>从{@link TemporalAccessor}转换为{@link LocalDate}</b>
     * <pre>{@code
     *     public static void main(String[] args) {
     *         System.out.println(toLocalDate(Year.now()));            //2023-01-01
     *         System.out.println(toLocalDate(YearMonth.now()));       //2023-01-01
     *         System.out.println(toLocalDate(LocalDate.now()));       //2023-01-10
     *         System.out.println(toLocalDate(LocalTime.now()));       //0001-01-01
     *         System.out.println(toLocalDate(LocalDateTime.now()));   //2023-01-10
     *     }
     * }</pre>
     * @param temporalAccessor {@link TemporalAccessor}
     * @return {@link LocalDate}
     */
    public static LocalDate toLocalDate(TemporalAccessor temporalAccessor) {
        return Optional.ofNullable(temporalAccessor).map(temporal -> temporal.query(localDateQuery())).orElse(null);
    }

    /**
     * <b>解析字符串为{@link LocalDate}</b>
     * @param date 日期格式字符串
     * @return {@link LocalDate}
     */
    public static LocalDate toLocalDate(String date) {
        return Times.parse(date, LocalDate.class);
    }

    /**
     * <b>将Object类型数据尝试转换为{@link LocalDate}</b>
     * @param source 未知类型对象
     * @return {@link LocalDate}
     * @see #milliseconds(Object)
     */
    public static LocalDate toLocalDate(Object source) {
        return parse(source, LocalDate.class);
    }

    //=============================转换成java.time.LocalTime===========================
    //=============================转换成java.time.LocalTime===========================
    //=============================转换成java.time.LocalTime===========================

    /**
     * <b>从时间戳转{@link LocalTime}</b>
     * @param milliseconds 时间戳
     * @return {@link LocalTime}
     */
    public static LocalTime toLocalTime(Long milliseconds) {
        return Optional.ofNullable(toInstant(milliseconds)).map(instant -> atDefaultZoneMapTo(instant, ZonedDateTime::toLocalTime)).orElse(null);
    }

    /**
     * <b>从{@link TemporalAccessor}转换为{@link LocalTime}</b>
     * <pre>{@code
     *     public static void main(String[] args) {
     *         System.out.println(toLocalTime(Year.now()));            //00:00
     *         System.out.println(toLocalTime(YearMonth.now()));       //00:00
     *         System.out.println(toLocalTime(LocalDate.now()));       //00:00
     *         System.out.println(toLocalTime(LocalTime.now()));       //10:48:14.366
     *         System.out.println(toLocalTime(LocalDateTime.now()));   //10:48:14.366
     *     }
     * }</pre>
     * @param temporalAccessor {@link TemporalAccessor}
     * @return {@link LocalTime}
     */
    public static LocalTime toLocalTime(TemporalAccessor temporalAccessor) {
        return Optional.ofNullable(temporalAccessor).map(temporal -> temporal.query(localTimeQuery())).orElse(null);
    }

    /**
     * <b>从{@link Date}转换为{@link LocalTime}</b>
     * @param date {@link Date}
     * @return {@link LocalTime}
     */
    public static LocalTime toLocalTime(Date date) {
        return Optional.ofNullable(date).map(Date::toInstant).map(instant -> atDefaultZoneMapTo(instant, ZonedDateTime::toLocalTime)).orElse(null);
    }

    /**
     * <b>解析字符串为{@link LocalTime}</b>
     * @param date 时间格式字符串
     * @return {@link LocalTime}
     */
    public static LocalTime toLocalTime(String date) {
        return Optional.ofNullable(date).map(Times::parse).map(LocalDateTime::toLocalTime).orElse(null);
    }

    /**
     * <b>将Object类型数据尝试转换为{@link LocalTime}</b>
     * @param source 未知类型对象
     * @return {@link LocalTime}
     * @see #milliseconds(Object)
     */
    public static LocalTime toLocalTime(Object source) {
        return parse(source, LocalTime.class);
    }

    //=============================转换成java.time.LocalDateTime===========================
    //=============================转换成java.time.LocalDateTime===========================
    //=============================转换成java.time.LocalDateTime===========================

    /**
     * <b>从时间戳转{@link LocalDateTime}</b>
     * @param milliseconds 时间戳
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime toLocalDateTime(Long milliseconds) {
        return atDefaultZoneMapTo(toInstant(milliseconds), ZonedDateTime::toLocalDateTime);
    }

    /**
     * <b>从{@link TemporalAccessor}转换为{@link LocalDateTime}</b>
     * <pre>{@code
     *     public static void main(String[] args) {
     *         System.out.println(toLocalDateTime(Year.now()));            //2023-01-01T00:00
     *         System.out.println(toLocalDateTime(YearMonth.now()));       //2023-01-01T00:00
     *         System.out.println(toLocalDateTime(LocalDate.now()));       //2023-01-10T00:00
     *         System.out.println(toLocalDateTime(LocalTime.now()));       //0001-01-01T13:02:23.418
     *         System.out.println(toLocalDateTime(LocalDateTime.now()));   //2023-01-10T13:02:23.418
     *     }
     * }</pre>
     * @param temporalAccessor {@link TemporalAccessor}
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime toLocalDateTime(TemporalAccessor temporalAccessor) {
        return Optional.ofNullable(temporalAccessor).map(temporal -> temporal.query(localDateTimeQuery())).orElse(null);
    }

    /**
     * <b>从{@link Date}转换为{@link LocalDateTime}</b>
     * @param date {@link Date}
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime toLocalDateTime(Date date) {
        return atDefaultZoneMapTo(toInstant(date), ZonedDateTime::toLocalDateTime);
    }

    /**
     * <b>解析字符串为{@link LocalDateTime}</b>
     * @param date 日期格式字符串
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime toLocalDateTime(String date) {
        return Optional.ofNullable(date).map(Times::parse).orElse(null);
    }

    /**
     * <b>将Object类型数据尝试转换为{@link LocalDateTime}</b>
     * @param source 未知类型对象
     * @return {@link LocalDateTime}
     * @see #milliseconds(Object)
     */
    public static LocalDateTime toLocalDateTime(Object source) {
        return parse(source, LocalDateTime.class);
    }


    //=============================转换成java.time.ZonedDateTime===========================
    //=============================转换成java.time.ZonedDateTime===========================
    //=============================转换成java.time.ZonedDateTime===========================

    /**
     * <b>从时间戳转{@link ZonedDateTime}</b>
     * @param milliseconds 时间戳
     * @return {@link ZonedDateTime}
     */
    public static ZonedDateTime toZonedDateTime(Long milliseconds) {
        return atDefaultZoneMapTo(toInstant(milliseconds), Function.identity());
    }

    /**
     * <b>从{@link TemporalAccessor}转换为{@link ZonedDateTime}</b>
     * <pre>{@code
     *     public static void main(String[] args) {
     *         System.out.println(toZonedDateTime(Year.now()));            //2023-01-01T00:00
     *         System.out.println(toZonedDateTime(YearMonth.now()));       //2023-01-01T00:00
     *         System.out.println(toZonedDateTime(LocalDate.now()));       //2023-01-10T00:00
     *         System.out.println(toZonedDateTime(LocalTime.now()));       //0001-01-01T13:02:23.418
     *         System.out.println(toZonedDateTime(LocalDateTime.now()));   //2023-01-10T13:02:23.418
     *     }
     * }</pre>
     * @param temporalAccessor {@link TemporalAccessor}
     * @return {@link ZonedDateTime}
     */
    public static ZonedDateTime toZonedDateTime(TemporalAccessor temporalAccessor) {
        return Optional.ofNullable(temporalAccessor).map(temporal -> temporal.query(zonedLocalDateTimeQuery())).orElse(null);
    }

    /**
     * <b>从{@link Date}转换为{@link ZonedDateTime}</b>
     * @param date {@link Date}
     * @return {@link ZonedDateTime}
     */
    public static ZonedDateTime toZonedDateTime(Date date) {
        return atDefaultZoneMapTo(toInstant(date), Function.identity());
    }

    /**
     * <b>解析字符串为{@link ZonedDateTime}</b>
     * @param date 日期格式字符串
     * @return {@link ZonedDateTime}
     */
    public static ZonedDateTime toZonedDateTime(String date) {
        return Optional.ofNullable(Times.parse(date)).map(DateUtils::toZonedDateTime).orElse(null);
    }

    /**
     * <b>将Object类型数据尝试转换为{@link ZonedDateTime}</b>
     * @param source 未知类型对象
     * @return {@link ZonedDateTime}
     * @see #milliseconds(Object)
     */
    public static ZonedDateTime toZonedDateTime(Object source) {
        return parse(source, ZonedDateTime.class);
    }

    //==================================日期格式化===================================
    //==================================日期格式化===================================
    //==================================日期格式化===================================

    /**
     * <b>将日期对象格式化为字符串</b>
     * @param pattern 日期格式
     * @param date 日期对象
     * @return 指定格式的日期字符串
     */
    public static String format(Date date, String pattern) {
        return new SimpleDateFormat(pattern).format(date);
    }

    /**
     * <b>将日期对象格式化为字符串</b>
     * @param pattern 日期格式
     * @param temporalAccessor 日期对象
     * @return 指定格式的日期字符串
     */
    public static String format(TemporalAccessor temporalAccessor, String pattern) {
        return ofPattern(pattern).format(temporalAccessor);
    }

    /**
     * <b>将日期对象格式化为字符串</b>
     * @param date 日期对象
     * @param pattern 日期格式
     * @return 指定格式的日期字符串
     */
    public static String format(LocalDate date, String pattern) {
        return ofPattern(pattern).format(date);
    }

    /**
     * <b>将日期对象格式化为字符串</b>
     * @param date 日期对象
     * @param formatter 日期格式
     * @return 指定格式的日期字符串
     */
    public static String format(LocalDate date, DateTimeFormatter formatter) {
        return formatter.format(date);
    }

    //==================================自定义日期解析格式===================================
    //==================================自定义日期解析格式===================================
    //==================================自定义日期解析格式===================================

    /**
     * <b>将日期字符串解析成日期对象</b>
     * @param date 日期字符串
     * @param patterns 日期格式
     * @return 按顺序解析，成功返回日期对象，解析失败返回null
     */
    public static Date parse(String date, String... patterns) {
        Optional<Date> firstNonNullDate = Arrays.stream(patterns)
                .map(SimpleDateFormat::new)
                .map(format -> Ex.tryCatch(() -> format.parse(date)).ignoreException(ParseException.class).orElse(null))
                .filter(Objects::nonNull)
                .findFirst();
        return firstNonNullDate.orElse(null);
    }

    /**
     * <b>将日期字符串解析成日期对象</b>
     * @see #parse(String, String...)
     * @see OffsetDateTime
     * @param date 日期字符串
     * @param patterns 日期格式
     * @return 按顺序解析，成功返回日期对象，解析失败返回null
     */
    public static ZonedDateTime parseToOffsetDateTime(String date, String... patterns) {
        return Optional.ofNullable(parse(date, patterns))
                .map(datetime -> atDefaultZoneMapTo(datetime.toInstant(), Function.identity()))
                .orElse(null);
    }

    /**
     * 日期格式化器
     * @param pattern 日期格式
     * @return {@link DateTimeFormatter}
     */
    public static DateTimeFormatter ofPattern(String pattern) {
        return DateTimeFormatter.ofPattern(pattern, Locale.getDefault());
    }

    //=============================从未知类型转换为日期类型===========================
    //=============================从未知类型转换为日期类型===========================
    //=============================从未知类型转换为日期类型===========================

    /**
     * 将未知的日期类型解析成指定的日期类型
     * <pre>{@code
     *     public static void main(String[] args) {
     *         System.out.println(parse("2022-12-12 12:12:12", Date.class));               //Mon Dec 12 12:12:12 CST 2022
     *         System.out.println(parse("2022-12-12 12:12:12", java.sql.Date.class));      //Mon Dec 12 12:12:12 CST 2022
     *         System.out.println(parse("2022-12-12 12:12:12", java.sql.Time.class));      //Mon Dec 12 12:12:12 CST 2022
     *         System.out.println(parse("2022-12-12 12:12:12", java.sql.Timestamp.class)); //2022-12-12 12:12:12.0
     *         System.out.println(parse("2022-12-12 12:12:12", Year.class));               //2022
     *         System.out.println(parse("2022-12-12 12:12:12", YearMonth.class));          //2022-12
     *         System.out.println(parse("2022-12-12 12:12:12", LocalDate.class));          //2022-12-12
     *         System.out.println(parse("2022-12-12 12:12:12", LocalTime.class));          //12:12:12
     *         System.out.println(parse("2022-12-12 12:12:12", LocalDateTime.class));      //2022-12-12T12:12:12
     *         System.out.println(parse("2022-12-12 12:12:12", OffsetDateTime.class));     //2022-12-12T12:12:12+08:00
     *     }
     * }</pre>
     * @param source 未知对象
     * @param targetDateType 目标日期类型
     * @return 返回对应的日期对象
     * @param <T> 期望得到的日期类型
     */
    public static <T> T parse(Object source, Class<T> targetDateType) {
        if ( source != null && targetDateType != null ) {
            Long milliseconds = milliseconds(source);
            Instant instant = toInstant(milliseconds);
            return to(instant, targetDateType);
        }
        return null;
    }

    /**
     * <b>毫秒时间戳转换为任意日期类型{@link Date}和{@link TemporalAccessor}及其子类类型</b>
     * @param millisecond 毫秒时间戳
     * @param targetDateType {@link Date}
     * @return 对应的日期类型
     * @param <T> 对应的日期类型T
     */
    public static <T> T to(long millisecond, Class<T> targetDateType) {
        return to(new Date(millisecond).toInstant(), targetDateType);
    }

    /**
     * <b>{@link Date}转换为任意日期类型{@link Date}和{@link TemporalAccessor}及其子类类型</b>
     * @see Date
     * @see TemporalAccessor
     * @param date {@link Date}
     * @param targetDateType {@link Date}
     * @return 对应的日期类型
     * @param <T> 对应的日期类型T
     */
    public static <T> T to(Date date, Class<T> targetDateType) {
        return to(date.toInstant(), targetDateType);
    }

    /**
     * <b>{@link Date}转换为任意日期类型{@link Date}和{@link TemporalAccessor}及其子类类型</b>
     * @see Date
     * @see TemporalAccessor
     * @param temporalAccessor {@link TemporalAccessor}
     * @param targetDateType {@link Date}
     * @return 对应的日期类型
     * @param <T> 对应的日期类型T
     */
    @SuppressWarnings("unchecked")
    public static <T> T to(TemporalAccessor temporalAccessor, Class<T> targetDateType) {
        if ( temporalAccessor != null && targetDateType != null ) {
            Instant instant = instantQuery().queryFrom(temporalAccessor);
            if ( Date.class.isAssignableFrom(targetDateType) )
                return (T) MethodConverterUtils.fromStaticMethodConverter.to(instant, (Class<Object>) targetDateType);
            else if ( TemporalAccessor.class.isAssignableFrom(targetDateType) ) {
                ZonedDateTime zonedDateTime = instant.atZone(ZoneId.systemDefault());
                return (T) MethodConverterUtils.fromStaticMethodConverter.to(zonedDateTime, (Class<Object>) targetDateType);
            }
        }
        return null;
    }

    /**
     * 是否支持转换目标日期类型
     * @param dateType 日期类型
     * @return true支持false不支持
     */
    public static boolean support(Class<?> dateType) {
        return Date.class.isAssignableFrom(dateType) || TemporalAccessor.class.isAssignableFrom(dateType);
    }

    //=============================日期查询访问相关===============================
    //=============================日期查询访问相关===============================
    //=============================日期查询访问相关===============================

    /**
     * <b>默认最小值的年份查询访问器</b>
     * <p>
     *     如果不存在年份则返回公元1年
     * </p>
     * @see TemporalAccessor
     * @see TemporalQuery
     * @see ChronoField#YEAR_OF_ERA
     * @see #getOrDefault(TemporalAccessor, ChronoField, Function)
     */
    public static final TemporalQuery<Year> YEAR_QUERY = temporal -> Year.of((int) getOrDefault(temporal, ChronoField.YEAR_OF_ERA, DateUtils::minimumValue));

    /**
     * <b>默认最小值的年份查询访问器</b>
     * <p>
     *     如果不存在年份则返回公元1年
     * </p>
     * @see TemporalAccessor
     * @see TemporalQuery
     * @see ChronoField#YEAR_OF_ERA
     * @see ChronoField#MONTH_OF_YEAR
     * @see #getOrDefault(TemporalAccessor, ChronoField, Function)
     */
    public static final TemporalQuery<YearMonth> YEAR_MONTH_QUERY = temporal -> YEAR_QUERY.queryFrom(temporal).atMonth((int) getOrDefault(temporal, ChronoField.MONTH_OF_YEAR, DateUtils::minimumValue));

    /**
     * 默认最小值的日期查询访问器
     * @see TemporalAccessor
     * @see TemporalQuery
     * @see ChronoField#YEAR_OF_ERA
     * @see ChronoField#MONTH_OF_YEAR
     * @see ChronoField#DAY_OF_MONTH
     * @see #getOrDefault(TemporalAccessor, ChronoField, Function)
     */
    public static final TemporalQuery<LocalDate> LOCAL_DATE_QUERY = temporal -> YEAR_MONTH_QUERY.queryFrom(temporal).atDay((int) getOrDefault(temporal, ChronoField.DAY_OF_MONTH, DateUtils::minimumValue));

    /**
     * 默认最小值的日期查询访问器
     * @see TemporalAccessor
     * @see TemporalQuery
     * @see ChronoField
     * @see #getOrDefault(TemporalAccessor, ChronoField, Function)
     */
    public static final TemporalQuery<LocalTime> LOCAL_TIME_QUERY = temporal -> {
        int hourOfDay = (int) getOrDefault(temporal, ChronoField.HOUR_OF_DAY, DateUtils::minimumValue);
        int minuteOfHour = (int) getOrDefault(temporal, ChronoField.MINUTE_OF_HOUR, DateUtils::minimumValue);
        int secondOfMinute = (int) getOrDefault(temporal, ChronoField.SECOND_OF_MINUTE, DateUtils::minimumValue);
        int nanoOfSecond = (int) getOrDefault(temporal, ChronoField.NANO_OF_SECOND, DateUtils::minimumValue);
        return LocalTime.of(hourOfDay, minuteOfHour, secondOfMinute, nanoOfSecond);
    };

    /**
     * 默认最小值的日期时间查询访问器
     * @see TemporalAccessor
     * @see TemporalQuery
     * @see ChronoField
     * @see #getOrDefault(TemporalAccessor, ChronoField, Function)
     */
    public static final TemporalQuery<LocalDateTime> LOCAL_DATE_TIME_QUERY = temporal -> LOCAL_DATE_QUERY.queryFrom(temporal).atTime(LOCAL_TIME_QUERY.queryFrom(temporal));

    /**
     * 默认最小值的日期时间查询访问器
     * @see ZonedDateTime
     * @see TemporalAccessor
     * @see TemporalQuery
     * @see ChronoField
     * @see #getOrDefault(TemporalAccessor, ChronoField, Function)
     */
    public static final TemporalQuery<ZonedDateTime> ZONED_LOCAL_DATE_TIME_QUERY = temporal -> LOCAL_DATE_QUERY.queryFrom(temporal)
                .atTime(LOCAL_TIME_QUERY.queryFrom(temporal))
                .atZone(ZoneId.systemDefault());

    /**
     * 默认最小值的时间戳查询访问器
     * @see TemporalAccessor
     * @see TemporalQuery
     * @see ChronoField
     * @see #getOrDefault(TemporalAccessor, ChronoField, Function)
     */
    public static final TemporalQuery<Instant> INSTANT_QUERY = temporal -> ZONED_LOCAL_DATE_TIME_QUERY.queryFrom(temporal).toInstant();

    /**
     * 默认最小值的时间戳查询访问器
     * @see #INSTANT_QUERY
     * @return {@link Instant}
     */
    public static TemporalQuery<Instant> instantQuery() {
        return INSTANT_QUERY;
    }

    /**
     * 默认最小值的年份查询访问器
     * @see #YEAR_QUERY
     * @return {@link Year}
     */
    public static TemporalQuery<Year> yearQuery() {
        return YEAR_QUERY;
    }

    /**
     * 默认最小值的年份月份查询访问器
     * @see #YEAR_QUERY
     * @return {@link YearMonth}
     */
    public static TemporalQuery<YearMonth> yearMonthQuery() {
        return YEAR_MONTH_QUERY;
    }

    /**
     * 默认最小值的日期查询访问器
     * @see #LOCAL_DATE_QUERY
     * @return {@link LocalDate}
     */
    public static TemporalQuery<LocalDate> localDateQuery() {
        return LOCAL_DATE_QUERY;
    }

    /**
     * 默认最小值的时间查询访问器
     * @see #LOCAL_DATE_QUERY
     * @return {@link LocalTime}
     */
    public static TemporalQuery<LocalTime> localTimeQuery() {
        return LOCAL_TIME_QUERY;
    }

    /**
     * 默认最小值的日期时间查询访问器
     * @see #LOCAL_DATE_QUERY
     * @return {@link LocalDateTime}
     */
    public static TemporalQuery<LocalDateTime> localDateTimeQuery() {
        return LOCAL_DATE_TIME_QUERY;
    }

    /**
     * 默认最小值的日期时间查询访问器
     * @see #ZONED_LOCAL_DATE_TIME_QUERY
     * @return {@link ZonedDateTime}
     */
    public static TemporalQuery<ZonedDateTime> zonedLocalDateTimeQuery() {
        return ZONED_LOCAL_DATE_TIME_QUERY;
    }

    /**
     * <b>获取日期中对应的值没有则返回该类型最小值</b>
     * <pre>{@code
     *     public static void main(String[] args) {
     *         System.out.println(getOrDefault(LocalTime.now(), ChronoField.YEAR, DateUtils::minimumValue));//-999999999
     *         System.out.println(getOrDefault(LocalTime.now(), ChronoField.YEAR, 0));                      //0
     *         System.out.println(getOrDefault(LocalTime.now(), ChronoField.YEAR_OF_ERA, 1));               //1
     *         System.out.println(getOrDefault(Year.now(), ChronoField.MONTH_OF_YEAR, 1));                  //1
     *         System.out.println(getOrDefault(Year.now(), ChronoField.DAY_OF_MONTH, 0));                   //0
     *         System.out.println(getOrDefault(Year.now(), ChronoField.HOUR_OF_DAY, 2));                    //2
     *         System.out.println(getOrDefault(Year.now(), ChronoField.MINUTE_OF_HOUR, 0));                 //0
     *         System.out.println(getOrDefault(Year.now(), ChronoField.MINUTE_OF_HOUR, 0));                 //0
     *     }
     * }</pre>

     * @see TemporalAccessor#query(TemporalQuery)
     * @see TemporalAccessor#get(TemporalField)
     * @param temporalAccessor {@link TemporalAccessor}
     * @param field {@link ChronoField}
     * @return 值
     */
    public static long getOrDefault(TemporalAccessor temporalAccessor, ChronoField field, long defaultValue) {
        temporalAccessor = ifInstantToZonedDateTime(temporalAccessor);
        return temporalAccessor.isSupported(field) ? temporalAccessor.get(field) : defaultValue;
    }

    /**
     * <b>获取日期中对应的值没有则返回该类型最小值</b>
     * <pre>{@code
     *     public static void main(String[] args) {
     *         System.out.println(getOrDefault(LocalTime.now(), ChronoField.YEAR, DateUtils::minimumValue));       //-999999999
     *         System.out.println(getOrDefault(LocalTime.now(), ChronoField.YEAR_OF_ERA, DateUtils::minimumValue));//1
     *         System.out.println(getOrDefault(Year.now(), ChronoField.MONTH_OF_YEAR, DateUtils::minimumValue));   //1
     *         System.out.println(getOrDefault(Year.now(), ChronoField.DAY_OF_MONTH, DateUtils::minimumValue));    //1
     *         System.out.println(getOrDefault(Year.now(), ChronoField.HOUR_OF_DAY, DateUtils::minimumValue));     //0
     *         System.out.println(getOrDefault(Year.now(), ChronoField.MINUTE_OF_HOUR, DateUtils::minimumValue));  //0
     *         System.out.println(getOrDefault(Year.now(), ChronoField.MINUTE_OF_HOUR, DateUtils::minimumValue));  //0
     *     }
     * }</pre>
     * @see TemporalAccessor#get(TemporalField)
     * @see TemporalAccessor#query(TemporalQuery)
     * @param temporalAccessor {@link TemporalAccessor}
     * @param field {@link ChronoField}
     * @return 值
     */
    public static long getOrDefault(TemporalAccessor temporalAccessor, ChronoField field, Function<ChronoField, Long> defaultValue) {
        temporalAccessor = ifInstantToZonedDateTime(temporalAccessor);
        if ( temporalAccessor.isSupported(field) )
            return temporalAccessor.get(field);
        return defaultValue.apply(field);
    }

    /**
     * 获取对应{@link ChronoField}的最小值
     * @param field {@link ChronoField}
     * @return 最小值
     */
    public static long minimumValue(ChronoField field) {
        return field.range().getMinimum();
    }

    /**
     * 设置{@link Instant}的时区并做映射
     * @param instant {@link Instant}
     * @param zonedDateTimeMapToFunc {@link Function}
     * @return 映射对应的类型
     * @param <T> instantFunc期望的类型
     */
    public static <T> T atDefaultZoneMapTo(Instant instant, Function<ZonedDateTime, T> zonedDateTimeMapToFunc) {
        return (instant != null && zonedDateTimeMapToFunc != null) ? zonedDateTimeMapToFunc.apply(instant.atZone(ZoneId.systemDefault())) : null;
    }

    /**
     * <b>如果是Instant则将其转换为{@link ZonedDateTime}</b>
     * @param temporalAccessor {@link TemporalAccessor}
     * @return {@link TemporalAccessor}
     */
    public static TemporalAccessor ifInstantToZonedDateTime(TemporalAccessor temporalAccessor) {
        return Instant.class == temporalAccessor.getClass() ? ((Instant) temporalAccessor).atZone(ZoneId.systemDefault()) : temporalAccessor;
    }

}
